Software applications that rely on automatic memory management are becoming more and more prevalent. Such applications may be implemented as traditional consumer desktop applications, in large scale data analysis computing systems, on high-performance web servers, on financial trading platforms, and can be included in ever-more demanding (e.g., memory intensive) websites. Such applications are even available for use on the billions of mobile phones that exist world-wide, as well as for implementation by embedded computing devices. Accordingly, reducing the costs (e.g., performance costs) of automatic memory management is of principal importance in best utilizing computing resources across the entire spectrum of available devices, and for achieving improved application throughput (performance), so as to improve the experience of users of such applications.
Many automatic memory management systems utilize garbage collection, such as may be implemented using generational garbage collectors, to remove memory objects that are no longer needed (e.g., outdated objects) by a given application, as part of managing memory that is assigned to the application by a computing device on which the application (program) is executing (running). Garbage collection can also be used to defragment a block of memory that is associated with a given program. Such a defragmentation process can group (move) live (active) memory objects together in memory and, as a result, free up larger blocks (sections, chunks, etc.) of available (free, unassigned, and so forth) memory space by eliminating portions of free memory that located between live objects (fragmented memory). These portions of unused (fragmented) memory may, for instance, be associated with objects that are no longer being used by the given application.
Garbage collection, however, can introduce some overhead in the associated application's main execution path. While some garbage collection work can be done incrementally, in parallel with the application, or even concurrently with the application, the cost of executing (memory) allocation operations (which may be referred to as allocation overhead) and write barriers still remain. This is even more apparent in garbage collectors that target low pause time (e.g., where garbage collection does affect user perception of performance during application execution) and require heavier write barriers (e.g., write barriers implemented with a relatively large number instructions, such as more than five instructions).
Such write barriers are generally emitted inline in compiled code (e.g., a set of software instructions) and, for implementations using generational garbage collection, are used to track inter-generational pointers (e.g., references from “old generation” objects to “young generation” objects). Such inter-generational pointers may need to be updated if a “young generation” object gets moved during a garbage collection process, in order to maintain its relationship with its associated “old generation” object or objects. Reducing the overhead associated with memory allocation operations (which can trigger garbage collection) and write barriers (which can be associated with an allocation instruction, a move instruction, a procedure call, a store instruction, or any other instruction in which references between memory objects can be changed) is desirable, as such reductions may provide improvements in throughput (performance) of an associated application.